package spade;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.provider.ProviderManager;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;


// This is a listener for XMPP packets
class XMPPListener implements PacketListener {
	Agent agent;
	public XMPPListener(Agent ag) {
		agent = ag;
	};
    public void processPacket(Packet packet) {
        System.out.println("XMPP: " + packet.toXML());
        System.out.println("TYPE: " + packet.getClass().toString());
        agent._other_messageCB(packet);
    };
};

// This is a listener for XMPP Message packets
class XMPPMessageListener implements PacketListener {
	Agent agent;
	public XMPPMessageListener(Agent ag) {
		agent = ag;
	};
    public void processPacket(Packet packet) {
        System.out.println("Message: " + packet.toXML());
        // TODO: Do something with the Message!
        agent._jabber_messageCB(packet);
    };
};

// This is a listener for XMPP Presence packets
class XMPPPresenceListener implements PacketListener {
	Agent agent;
	public XMPPPresenceListener(Agent ag) {
		agent = ag;
	};
    public void processPacket(Packet packet) {
        System.out.println("Presence: " + packet.toXML());
        // TODO: Do something with the Presence!
    };
};

//This is a listener for XMPP IQ packets
class XMPPIQListener implements PacketListener {
	Agent agent;
	public XMPPIQListener(Agent ag) {
		agent = ag;
	};
    public void processPacket(Packet packet) {
        System.out.println("IQ: " + packet.toXML());
        // TODO: Do something with the IQ!
    };
};

public class Agent extends MessageReceiver {

    public XMPPListener xmppl;
    XMPPPresenceListener pl;
    XMPPMessageListener ml;
    XMPPIQListener iql;
	private AID _aid;
	private String _jabber = null;
	private String _serverplatform;
	private Behaviour _defaultbehaviour = null;
	private HashMap<Behaviour,MessageTemplate> _behaviourList = new HashMap<Behaviour,MessageTemplate>();
    private boolean _alive = true;
    private ReentrantLock _alivemutex = new ReentrantLock();
    private boolean _forceKill = false;
    private JID jid;
    private HashMap<Object,Object> _jabber_mailbox = new HashMap<Object,Object>();

    private boolean _waitingForRoster = false;  // Indicates that a request for the roster is in progress

    private final ReentrantLock behavMutex = new ReentrantLock();
    private final Condition behavioursGo = behavMutex.newCondition(); // Condition to synchronise behaviours
    private boolean _running = false;
    public String server;
    public int port;
    public XMPPConnection jabber;
    //public jabberProcess jabber_process;

    @SuppressWarnings("deprecation")
	public Agent (String agentjid, String password, Integer portnumber) {
        /**
        inits an agent with a JID (user@server) and a platform JID (acc.platformserver)
        **/
        super();

        Vector<String> addresses = new Vector<String>();
        addresses.add("xmpp://"+agentjid);
        _aid = new AID(agentjid, addresses);

        jid = new JID(agentjid);
        _serverplatform = jid.getDomain();
        server = jid.getDomain();

        if (portnumber == null) port = 5222;
        else port = portnumber.intValue();

        // Configure the connection
        ConnectionConfiguration config = new ConnectionConfiguration(server, port);
        config.setCompressionEnabled(false);
		config.setSASLAuthenticationEnabled(true);

		// Connect
        jabber = new XMPPConnection(config);

        try {
        	jabber.connect();
            _register(password);
        }
        catch (Exception e) {
            System.out.println("### Could not register agent " + agentjid);
            this.stop();
        };

        //Add Presence Control Behaviour
        //this.addBehaviour(Agent.PresenceBehaviour(), Behaviour.MessageTemplate(Presence()))
        // TODO: Do this the proper way
        XMPPPresenceListener pl = new XMPPPresenceListener(this);
        PacketFilter pfilter = new PacketTypeFilter(Presence.class);
        jabber.addPacketListener( pl, pfilter );
    };

    /**
    def _receive(self, block = False, timeout = None, template = None):
        try:
            if not template: return MessageReceiver.MessageReceiver._receive(self, block, timeout)
            elif template and block and timeout:
                i = timeout
                while i > 0:
                    #timeout becomes the amount of 'tries' to receive a message
                    msg = self._receive(block=True, timeout=timeout, template=None)
                    if msg:
                        print "_RECEIVE HAS A MSG:", str(msg)
                        if template.match(msg):
                            print "_RECEIVE HAS MADE A MATCH"
                            return msg
                        else:
                            print "_RECEIVE NO MATCH"
                            self.postMessage(msg)
                    i -= 1
                return None
            else:
                while True:
                    msg = MessageReceiver.MessageReceiver._receive(self, True, 0.1)
                    if msg:
                        if template.match(msg): return msg
                        else: #self.postMessage(msg)
                            pass

        except:
            _exception = sys.exc_info()
            if _exception[0]:
                print '\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip()
    **/

     public ACLMessage newMessage() {
		/**Creates and returns an empty ACL message**/
		return new ACLMessage();
     }

     /**
      TODO: Depende de la libreria de XMPP smack

    private void _jabber_presenceCB(self, conn, mess):
	"""
	presence callback
	manages jabber stanzas of the 'presence' protocol
	"""

	#frm=None

	frm = mess.getFrom()
        #frm = AID.aid(str(mess.getFrom()), ['xmpp://'+str(mess.getFrom())])
        typ = str(mess.getType())
        status = str(mess.getStatus())
        show = str(mess.getShow())
        role = None
        affiliation = None

        children = mess.getTags(name='x',namespace='http://jabber.org/protocol/muc#user')
        for x in children:
            for item in x.getTags(name='item'):
                role = item.getAttr('role')
                affiliation = item.getAttr('affiliation')
#
#        #check for MUC presence
#		if ifrm.getDomain() == self.getMUC():
#			if self._muc_list.has_key(str(ifrm.getNode())):
#				self._muc_list[ifrm.getNode()].presenceCB(mess)
#
#		else:
#
#
#        if typ in ['subscribe']:
#		# Call the subscribe handler
#		if self._subscribeHandler(frm, typ, status, show):
#			reply = xmpp.Presence(mess.getFrom(), 'subscribed')
#			conn.send(reply)
#			return
#	elif typ in ['subscribed']:
#		# Subscription confirmation
#		print color_green + "Subscription to " + color_yellow + str(ifrm) + color_green  +" resolved" + color_none
#		return
#	elif typ in ['unsubscribe']:
#		# Call the unsubscribe handler
#		if self._unsubscribeHandler(frm, typ, status, show):
#			reply = xmpp.Presence(mess.getFrom(), 'unsubscribed')
#			conn.send(reply)
#		return
#	elif typ in ['unsubscribed']:
#		# Subscription denial
#		print color_red + "WARNING: Subscription to " + color_yellow + str(ifrm) + color_red  +" denied or cancelled" + color_none
#		return
#
#
#        else:
#			# Unsupported presence message
#			print color_yellow + "Unsupported presence message: " + str(mess.getType()) + color_none
#			return

        try:
	 	# Pass the FIPA-message to the behaviours
		#print "BEHAVIOURLIST: ", str(self._behaviourList)
		for b in self._behaviourList.keys():
		       #print "BEHAVIOUR LIST", str(b)
		       b.managePresence(frm, typ, status, show, role, affiliation)

		self._defaultbehaviour.managePresence(frm, typ, status, show, role, affiliation)
	except Exception, e:
	 	#There is not a default behaviour yet
		print "EXCEPTION: ", str(e)

	#self._roster = conn.getRoster()

**/

    public final void _jabber_messageCB(Packet mess) {
        /**
        message callback
        read the message envelope and post the message to the agent
        **/

    	System.out.println("_jabber_messageCB: " + mess.toXML());

    	Iterator<PacketExtension> it = mess.getExtensions().iterator();
    	while (it.hasNext()) {
    		PacketExtension pe = it.next();
    		String ns = pe.getNamespace();
    		if (ns == "jabber:x:fipa") {
    			// FIPA match
    			ACLMessage ACLmsg = new ACLMessage();

    			// Get the sender and the receiver
    			AID sender = new AID(mess.getFrom().toString());
    			ACLmsg.setSender(sender);
    			AID receiver = new AID(mess.getTo().toString());
    			ACLmsg.addReceiver(receiver);

    			// Get the rest of the properties
    			Iterator<String> its = mess.getPropertyNames().iterator();
    			while (its.hasNext()) {
    				String pname = its.next();
    				/**if (pname == "from") {
    					AID sender = new AID(mess.getProperty(pname).toString());
    					ACLmsg.setSender(sender);
    				};
    				if (pname == "to") {
    					AID receiver = new AID(mess.getProperty(pname).toString());
    					ACLmsg.addReceiver(receiver);
    				};**/
    				if (pname == "reply_to") {
    					AID repto = new AID(mess.getProperty(pname).toString());
    					ACLmsg.addReplyTo(repto);
    				};
    				if (pname == "performative") {
    					ACLmsg.setPerformative(mess.getProperty(pname).toString());
    				};
    				if (pname == "language") {
    					ACLmsg.setLanguage(mess.getProperty(pname).toString());
    				};
    				if (pname == "ontology") {
    					ACLmsg.setOntology(mess.getProperty(pname).toString());
    				};
    				if (pname == "encoding") {
    					ACLmsg.setEncoding(mess.getProperty(pname).toString());
    				};
    				// TODO: Implement the rest of boring fipa message fields
    			};
    			ACLmsg.setContent(((Message)mess).getBody());
    		};
    	};

        /**for child in mess.getChildren():
         *
         *
            if (child.getNamespace() == "jabber:x:fipa") {
                // It is a jabber-fipa message
                ACLMessage ACLmsg = ACLMessage();
                //TODO: ACLmsg._attrs.update(mess.attrs)
                try:
                    #Clean
                    del ACLmsg._attrs["from"]
                except:
                    pass
                try:
                    #Clean
                    del ACLmsg._attrs["to"]
                except:
                    pass
                ACLmsg.setContent(mess.getBody())

          **** HASTA AQUI PORTADO LO ANTERIOR


                # Rebuild sender and receiver

                # Check wether there is an envelope
                if child.getTag("envelope"):
                    # There is an envelope; use it to build sender and receivers
                    xc = XMLCodec.XMLCodec()
                    envelope = xc.parse(str(child.getTag("envelope")))
                    if envelope.getFrom():
						try:
							#ACLmsg.setSender(envelope.getFrom().getStripped())
							ACLmsg.setSender(envelope.getFrom().getStripped())
						except:
							ACLmsg.setSender(envelope.getFrom())
                    else:
                        ACLmsg.setSender(AID.aid(str(mess.getFrom().getStripped()), ["xmpp://"+str(mess.getFrom().getStripped())]))
                    if envelope.getIntendedReceiver():
                        for ir in envelope.getIntendedReceiver():
                            ACLmsg.addReceiver(ir)
                    else:
                        ACLmsg.addReceiver(AID.aid(str(mess.getTo().getStripped()), ["xmpp://"+str(mess.getTo())]))
                else:
                    ACLmsg.setSender(AID.aid(str(mess.getFrom().getStripped()), ["xmpp://"+str(mess.getFrom().getStripped())]))
                    ACLmsg.addReceiver(AID.aid(str(mess.getTo().getStripped()), ["xmpp://"+str(mess.getTo().getStripped())]))
                self.postMessage(ACLmsg)
                if raiseFlag: raise xmpp.NodeProcessed  # Forced by xmpp.py for not returning an error stanza
                return True

        # Not a jabber-fipa message
               postMessage(mess);
    **/
    }

    public final void _other_messageCB(Packet mess) {
	/**
	non jabber:x:fipa chat messages callback
        //if there is a mailbox with type and id registered. we store the message
	 **/
       /** Message.Type typ = mess.getType();
        String id  = mess.getID();
        if (_jabber_mailbox.containsKey(typ)) {
           if (_jabber_mailbox.get(typ).containsKey(id)) {
                _jabber_mailbox.get(typ).get(id).add(mess);
           }
        }
        **/
    }

 /**   public void register_mailbox(typ,id) {
        /**
        Registers a jabber mailbox with type and id
        **//**
        if (_jabber_mailbox.containsKey(typ)) {
            if (!_jabber_mailbox.get(typ).containsKey(id))
                _jabber_mailbox.get(typ).put(id,new Stack());
        }
        else {
            _jabber_mailbox.put(typ, new HashMap());
            _jabber_mailbox.get(typ).put(id, new Stack());
        }
    }**/

    /**def unregister_mailbox(self,typ,id):
        """
        Unregisters a jabber mailbox with type and id
        """
        if self._jabber_mailbox.has_key(typ):
            if self._jabber_mailbox[typ].has_key(id):
                del self._jabber_mailbox[typ][id]
    **/

  /**  public Message jabber_receive( Object typ, Object id ) {
        /**
        Returns a jabber message from the mailbox with type and id
        **/
/**        if (_jabber_mailbox.containsKey(typ)) {
        	if (_jabber_mailbox.get(typ).containsKey(id)) {

        		if (!_jabber_mailbox.get(typ).get(id).isEmpty())
                	return _jabber_mailbox.get(typ).get(id).pop();
        	}
        }

        return null;

    }
**/
    public AID getAID() {
	/**
	returns AID
	**/
        return _aid;
    }

    public void setAID(AID newaid) {
        /**
        sets a new AID
        **/
        _aid = newaid;
    }

    public void addAddress(String addr) {
        _aid.addAddress(addr);
    }

    public String getAgentName() {
	return _aid.getName();
    }

    public AID getAMS() {
	/**
	returns the AMS aid
	**/
    	Vector<String> addr = new Vector<String>();
    	addr.add("xmpp://ams."+_serverplatform);
        return new AID("ams." + _serverplatform, addr);
    }

    public AID getDF() {
	/**
	returns the DF aid
	**/
    	Vector<String> addr = new Vector<String>();
    	addr.add("xmpp://df."+_serverplatform);
        return new AID("df." + _serverplatform, addr);
    }

    public String getMUC() {
	/**
	returns the MUC JID
	**/
	return "muc." + _serverplatform;
    }

    public String getSpadePlatformJID() {
	/**
	returns the SPADE JID (string)
	**/
        return "acc." + _serverplatform;
    }

    public String getDomain() {
        /**
        returns the SPADE server domain
        **/
        return _serverplatform;
    }



    public void send(ACLMessage ACLmsg) {
	/**
	sends an ACLMessage
	**/
        // Check for the sender field!!! (mistake #1)
        if ( ACLmsg.getSender() != null ) {
            ACLmsg.setSender(this.getAID());
        }

        this._sendTo(ACLmsg, ACLmsg.getReceivers());
    }

    private void _sendTo( ACLMessage ACLmsg, Vector<AID> tojid) {
        /**
        sends an ACLMessage to a specific JabberID
        **/

        //TODO: xenv = xmpp.protocol.Node('jabber:x:fipa x');
        //Envelope envelope = new Envelope();
        //boolean generate_envelope = false;
        //If there is more than one address in the sender or
        //the only address is not an xmpp address,
        //we need the full sender AID field

        /**    if ( ACLmsg.getSender().getAddresses().size() > 1 || !ACLmsg.getSender().getAddresses().firstElement().contains("xmpp") ) {
                envelope.setFrom(ACLmsg.getSender());
                generate_envelope = true;
            }


            Iterator<AID> it = ACLmsg.getReceivers().iterator();
            while (it.hasNext()) {
                //For every receiver,
                //if there is more than one address in the receiver or
                //the only address is not an xmpp address,
                //we need the full receiver AID field
            	AID aid = it.next();
            	Vector<String> addresses = aid.getAddresses();
                if (addresses.size() > 1 || !addresses.firstElement().contains("xmpp")) {
                    envelope.addTo(aid);
                    generate_envelope = true;
                }
            }

            //The same for 'reply_to'
            it = ACLmsg.getReplyTo().iterator();
            while (it.hasNext()) {
                //For every receiver,
                //if there is more than one address in the receiver or
                //the only address is not an xmpp address,
                //we need the full receiver AID field
            	AID aid = it.next();
            	Vector<String> addresses = aid.getAddresses();
                if (addresses.size() > 1 || !addresses.firstElement().contains("xmpp")) {
                    envelope.addTo(aid);
                    generate_envelope = true;
                }
            }


        //Generate the envelope ONLY if it is needed
        if (generate_envelope) {
            XMLCodec xc = new XMLCodec();
            String envxml = xc.encodeXML(envelope);
            //xenv['content-type']='fipa.mts.env.rep.xml.std'
            //xenv.addChild(node=simplexml.NodeBuilder(envxml).getDom())
        }
	**/

        //For each of the receivers, try to send the message
        Iterator<AID> jids = tojid.iterator();
        while (jids.hasNext()) {
        	AID to = jids.next();
            boolean isjabber = false;
            String jabber_id = "";
            Message jabber_msg = new Message();

            Iterator<String> addresses = to.getAddresses().iterator();
            while (addresses.hasNext()) {
            	String address = addresses.next();
                if (address.contains("xmpp://")) {
                    //If there is a jabber address for this receiver, send the message directly to it
                    jabber_id = address.split("://")[1];
                    isjabber = true;
                    break;
                }
            }
            if ( isjabber && jabber_id.contains(this.getDomain()) ) {
            	//TODO: Check SMACK
                //jabber_msg = xmpp.protocol.Message(jabber_id, xmlns="")
                //jabber_msg.attrs.update(ACLmsg._attrs)
                //jabber_msg.addChild(node=xenv)
                //jabber_msg["from"]=self.getAID().getName()
                jabber_msg.setBody(ACLmsg.getContent());
            }
            else {
                //I don't understand this address, relay the message to the platform
                //jabber_msg = xmpp.protocol.Message(self.getSpadePlatformJID(), xmlns="")
            	//TODO: Check SMACK
                jabber_id = this.getSpadePlatformJID();
                //jabber_msg.attrs.update(ACLmsg._attrs)
                //jabber_msg.addChild(node=xenv)
                //jabber_msg["from"]=self.getAID().getName()
                jabber_msg.setBody(ACLmsg.getContent());
            }

            this.jabber.sendPacket(jabber_msg);

        }
    }

    private void _kill() {
	/**
	kills the agent
	**/
	this._forceKill = true;
    }

    public boolean isRunning() {
	/**
	returns wether an agent is running or not
	**/
	return this._alive;
    }

    public boolean stop(long timeout) {
	/**
	Stops the agent execution and blocks until the agent dies
	**/
    	long to;
    	this._kill();
    	if (timeout > 0) {
    		to = System.currentTimeMillis()/1000 + timeout;
    		while ( this._alive && (System.currentTimeMillis()/1000) < to )
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    	}
    	// No timeout (true blocking)
    	else {
    		while ( this._alive )
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    	}
    	return true;
    }

    public boolean forceKill() {
            return this._forceKill;
    }

    public void _setup() {
	/**
	setup agent method. configures the agent
	must be overridden
    **/
    }

    public void takeDown() {
	/**
	stops the agent
	must be overridden
    (kind of a "onEnd" for the agent)
    **/
    }


    public void run() {
        /**
        periodic agent execution
        **/
        //Init The agent
        this._setup();
        this.behavMutex.lock();
        this._running = true;
        this.behavioursGo.notifyAll();
        this.behavMutex.unlock();

        //Start the Behaviours
        if (this._defaultbehaviour != null)
            this._defaultbehaviour.start();

        //Main Loop
        while ( !this.forceKill() ) {
            try {
                //Check for queued messages
                boolean proc = false;
                //Vector<Behaviour> toRemove = new Vector<Behaviour>();  /// List of behaviours to remove after this pass
                ACLMessage msg = this._receive(true, 0.01, null);
                if (msg != null) {
                    Iterator<Behaviour> bL = this._behaviourList.keySet().iterator();
                    while (bL.hasNext()) {
                        Behaviour b = bL.next();
                        MessageTemplate  t =  this._behaviourList.get(b);

                        if (t != null) {
                            if (t.match(msg) == true) {
                                /**if type(b) == types.ClassType or type(b) == types.TypeType:
                                    if b.onetime:
                                        toRemove.append(b)
                                    b = b()
                                    b.setAgent(self)
                                    b.postMessage(msg)
                                    b.start()
                            	}
                                else {**/
                                    b.postMessage(msg);
                                }
                            proc = true;
                            //print ">>>>>>MESSAGE " + str(msg) + " POSTEADO A BEHAV " + str(b)
                        }
                    }

                    if (proc == false) {
                        //print ">>>MESSAGE", str(msg), " DOES NOT MATCH BEHAVIOUR ", str(b)
                        if (this._defaultbehaviour != null)
                               this._defaultbehaviour.postMessage(msg);
                    }
                    /*for beh in toRemove:
                        self._behaviourList.remove(beh)*/
                }
            }
            catch (Exception e) {
                //print "Agent", self.getName(), "Exception in run:", str(e)
            	e.printStackTrace();
                this._kill();
            }
        }

        this._shutdown();
    }

    public void setDefaultBehaviour(Behaviour behaviour) {
	/**
	sets a Behavior as Default
	**/
        this._defaultbehaviour = behaviour;
        behaviour.setMyAgent(this);
    }

    public Behaviour getDefaultBehaviour() {
	/**
	returns the default behavior
	**/
        return this._defaultbehaviour;
    }

    public void addBehaviour(Behaviour behaviour, MessageTemplate template) {
	/**
	adds a new behavior to the agent
	**/
    	this._behaviourList.put(behaviour,template);
        behaviour.setMyAgent(this);
        behaviour.start();
    }


    public void removeBehaviour(Behaviour behaviour) {
	/**
	removes a behavior from the agent
	**/

    	behaviour.kill();
    	this._behaviourList.remove(behaviour);
    }






    private void _register(String password) {
        /**
        registers the agent in the Jabber server
        **/
    	boolean registered = true;

        jid = new JID(this._aid.getName());
        //String name = jid.getNode();
        String name = jid.getStripped();

        //c = ''
        //TODO: while not self.jabber.connect(use_srv=None): time.sleep(0.005)
        //print "### Agent %s got connected to the server"%(self._aid.getName())

        //TODO:  Que pasa si no nos identificamos? Hay que controlarlo!!!
        //       Registrarse automaticamente o algo..
        //this.jabber.auth(name,password,"spade");

        try {
    		// Add the listeners with their filters
    		// Create 3 listeners (IQ, MESSAGE and PRESENCE)
    		//xmppl = new XMPPListener(this);
    		ml = new XMPPMessageListener(this);
    		pl = new XMPPPresenceListener(this);
    		iql = new XMPPIQListener(this);

    		// Try to make login
			jabber.login(name, password, "spade");

		}
        catch (Exception e) {
		    // Something went wrong, possibly the login
			System.out.println("EXCEPTION");
			System.out.println(e);
			registered = false;
		};

		if (!registered) {
		    // Not registered on the jabber server
			try {
			    // This is the dict of user properties
				HashMap<String, String> propert = new HashMap<String,String>();

				// We add the name
				// TODO: Add this well
				propert.put("name",jid.getNode());

				// Try to create the account
				jabber.getAccountManager().createAccount(jid.getNode(), password, propert);

				// Disconnect and reconnect
				jabber.disconnect();
				jabber.connect();

				// Try to login again
				jabber.login(name, password, "spade");
			}
			catch (Exception e) {
			    // This is really fucked up
				System.out.println("EXCEPTION");
				System.out.println(e);
			};
		};

		// Add each listener with each filter
		PacketFilter mfilter = new PacketTypeFilter(Message.class);
    	PacketFilter pfilter = new PacketTypeFilter(Presence.class);
    	PacketFilter iqfilter = new PacketTypeFilter(IQ.class);

		//jabber.addPacketListener(xmppl, null);
		jabber.addPacketListener(ml, mfilter);
		jabber.addPacketListener(pl, pfilter);
		jabber.addPacketListener(iql, iqfilter);

        /**
        self.jabber.RegisterHandler('message',self._jabber_messageCB)
        self.jabber.RegisterHandler('presence',self._jabber_messageCB)
        self.jabber.RegisterHandler('iq',self._jabber_messageCB)
        #self.jabber.RegisterHandler('presence',self._jabber_presenceCB)
        **/

        //jabber_process = new jabberProcess(this.jabber, this);
        //this.jabber_process.start();
        //print "### Agent %s: Started jabber process"%(self._aid.getName())

        // Request roster and send initial presence
        //self.jabber.sendInitPresence()

    }

    private void _shutdown() {
        //Stop the Behaviours
    	Iterator<Behaviour> it = this._behaviourList.keySet().iterator();
    	while (it.hasNext()) {
                it.next().kill();
    	}

        if (this._defaultbehaviour != null)
            this._defaultbehaviour.kill();

        //DeInit the Agent
        this.takeDown();

        if (this._alivemutex.tryLock()) {
            //if ( !this.jabber_process.forceKill() )
            //    this.jabber_process._kill();  // Kill jabber thread
            //this._alive = false;
        }
        this._alivemutex.unlock();

        this._kill();  // Doublecheck death
    }

} //of Agent class

/**class jabberProcess extends Thread {

	XMPPConnection jabber;
    boolean _forceKill = false;
    Agent _owner;

	jabberProcess (XMPPConnection socket, Agent owner) {
        super();
		jabber = socket;
        _owner = owner;
	}

    public void _kill() {
    	this._forceKill = true;
    }

    public boolean forceKill() {
    	return this._forceKill;
    }

	public void run() {
		/**
		periodic jabber update
        **
		int err = 1;
        while ( !this.forceKill() ) {
        			//TODO: err = self.jabber.Process(0.4)
        		    if (err == null || err == 0) {  // None or zero the integer, socket closed
        			//print color_red + "Agent disconnected: " + color_yellow + str(self._owner.getAID().getName()) + color_red + " (dying)" + color_none
        					this._kill();
        					this._owner.stop();
        		    }
        }
	}
}**/